'use strict'; const { Document } = require('/document.js'); const { DocumentCommand } = require('/commands.js'); const { Dialog, DialogResult, UnitType } = require('/dialog.js'); const { DiffusionCurveSet, DiffusionFill, FillDescriptor } = require('/fills.js'); const { RGBA8 } = require('/colours.js'); const { Transform, CurveBuilder } = require('/geometry.js'); function isOk(result) { return (result?.value ?? result) === DialogResult.Ok.value; } function randomVividColour(rFactor, gFactor, bFactor) { const h = Math.random() * 360; const s = 0.7 + Math.random() * 0.3; const v = 0.6 + Math.random() * 0.4; const c = v * s, x = c * (1 - Math.abs((h / 60) % 2 - 1)), m = v - c; let r = 0, g = 0, b = 0; if (h < 60) { r = c; g = x; b = 0; } else if (h < 120) { r = x; g = c; b = 0; } else if (h < 180) { r = 0; g = c; b = x; } else if (h < 240) { r = 0; g = x; b = c; } else if (h < 300) { r = x; g = 0; b = c; } else { r = c; g = 0; b = x; } const rv = Math.min(255, Math.max(0, Math.round((r + m) * 255 * rFactor))); const gv = Math.min(255, Math.max(0, Math.round((g + m) * 255 * gFactor))); const bv = Math.min(255, Math.max(0, Math.round((b + m) * 255 * bFactor))); return RGBA8(rv, gv, bv, 255); } function makePressureCurve(startP, endP) { const cb = CurveBuilder.create(); cb.begin({ x: 0, y: Math.max(0, Math.min(1, startP)) }); cb.lineToXY(1, Math.max(0, Math.min(1, endP))); return cb.createCurve(); } function applyLineDiffusionFill(node, lineCount, minLen, maxLen, minBlur, maxBlur, minStrength, maxStrength, minPressure, maxPressure, rFactor, gFactor, bFactor, angleFactor,linkcolour) { const bounds = node.baseBox; const curveSet = DiffusionCurveSet.create(); for (let i = 0; i < lineCount; i++) { const cx = 0.05 + Math.random() * 0.90; const cy = 0.05 + Math.random() * 0.90; const len = minLen + Math.random() * (maxLen - minLen); const halfLen = len / 2; const angle = angleFactor === -1 ? Math.random() * Math.PI * 2 : angleFactor; const start = { x: cx - Math.cos(angle) * halfLen, y: cy - Math.sin(angle) * halfLen }; const end = { x: cx + Math.cos(angle) * halfLen, y: cy + Math.sin(angle) * halfLen }; const leftColour = randomVividColour(rFactor, gFactor, bFactor); const rightColour = randomVividColour(rFactor, gFactor, bFactor); try { if (linkcolour) {curveSet.addLine(start, end, leftColour, leftColour);} // link them else {curveSet.addLine(start, end, leftColour, rightColour);} const idx = curveSet.curveCount - 1; const blur = minBlur + Math.random() * (maxBlur - minBlur); const strength = minStrength + Math.random() * (maxStrength - minStrength); curveSet.setCurveBlur(idx, Math.max(0, Math.min(1.0, blur))); curveSet.setCurveStrength(idx, Math.max(0, Math.min(2.0, strength))); const startP = minPressure + Math.random() * (maxPressure - minPressure); const endP = minPressure + Math.random() * (maxPressure - minPressure); curveSet.setCurvePressure(idx, makePressureCurve(startP, endP)); } catch(e) { console.log(`Line ${i} skipped: ${e.message}`); } } const fillTransform = Transform.multiply( Transform.createTranslate(bounds.x, bounds.y), Transform.createScale(bounds.width, bounds.height) ); node.brushFillInterface.fillDescriptor = FillDescriptor.create( DiffusionFill.create(curveSet), true, fillTransform, undefined, false ); console.log(`Applied ${curveSet.curveCount} diffusion lines`); } // ---- MAIN ---- const doc = Document.current; if (!doc) { console.log('ERROR: No document open.'); } else { const selectedNodes = doc.selection.nodes.filter(n => n.brushFillInterface !== null).toArray(); if (selectedNodes.length === 0) { console.log('Please select one or more shapes first.'); } else { const dlg = Dialog.create('Diffusion Line Fill'); const col = dlg.addColumn(); const g1 = col.addGroup('Straight Lines'); const countCtrl = g1.addUnitValueEditor('Number of lines (max 500)', UnitType.Number, UnitType.Number, 50, 1, 500).setPrecision(0); // const g2 = col.addGroup('Min line length (0–1)'); const minLenCtrl = g1.addUnitValueEditor('Min line length (0–5)', UnitType.Number, UnitType.Number, 0.05, 0.01, 5).setPrecision(3); // const g3 = col.addGroup('Max line length (0–1)'); const maxLenCtrl = g1.addUnitValueEditor('Max line length (0–5)', UnitType.Number, UnitType.Number, 0.4, 0.01, 5).setPrecision(3); // const g4 = col.addGroup('Min blur (0–1)'); const minBlurCtrl = g1.addUnitValueEditor('Min blur (0–1)', UnitType.Number, UnitType.Number, 0.1, 0.0, 1.0).setPrecision(2); // const g5 = col.addGroup('Max blur (0–1)'); const maxBlurCtrl = g1.addUnitValueEditor('Max blur (0–1)', UnitType.Number, UnitType.Number, 0.6, 0.0, 1.0).setPrecision(2); // const g6 = col.addGroup('Min strength (0–2)'); const minStrCtrl = g1.addUnitValueEditor('Min strength (0–2)', UnitType.Number, UnitType.Number, 0.5, 0.0, 2.0).setPrecision(2); // const g7 = col.addGroup('Max strength (0–2)'); const maxStrCtrl = g1.addUnitValueEditor('Max strength (0–2)', UnitType.Number, UnitType.Number, 1.5, 0.0, 2.0).setPrecision(2); // const g8 = col.addGroup('Min pressure (0–1)'); const minPresCtrl = g1.addUnitValueEditor('Min pressure (0–1)', UnitType.Number, UnitType.Number, 0.1, 0.0, 1.0).setPrecision(2); // const g9 = col.addGroup('Max pressure (0–1)'); const maxPresCtrl = g1.addUnitValueEditor('Max pressure (0–1)', UnitType.Number, UnitType.Number, 1.0, 0.0, 1.0).setPrecision(2); // const g10 = col.addGroup('Red channel factor (0–10)'); const rCtrl = g1.addUnitValueEditor('Red channel factor (0–10)', UnitType.Number, UnitType.Number, 1.0, 0.0, 10.0).setPrecision(2); // const g11 = col.addGroup('Green channel factor (0–10)'); const gCtrl = g1.addUnitValueEditor('Green channel factor (0–10)', UnitType.Number, UnitType.Number, 1.0, 0.0, 10.0).setPrecision(2); // const g12 = col.addGroup('Blue channel factor (0–10)'); const bCtrl = g1.addUnitValueEditor('Blue channel factor (0–10)', UnitType.Number, UnitType.Number, 1.0, 0.0, 10.0).setPrecision(2); const angleFactor = g1.addUnitValueEditor('Angle (-1 Random, 6.28 max)', UnitType.Number, UnitType.Number, -1.0, -1.0, 6.28).setPrecision(2); const linkcolour = g1.addSwitch("Link colours", false); dlg.initialWidth = 430; const result = dlg.runModal(); if (isOk(result)) { const count = Math.min(100, Math.max(1, Math.round(countCtrl.value))); const minLen = Math.min(minLenCtrl.value, maxLenCtrl.value); const maxLen = Math.max(minLenCtrl.value, maxLenCtrl.value); const minBlur = Math.min(minBlurCtrl.value, maxBlurCtrl.value); const maxBlur = Math.max(minBlurCtrl.value, maxBlurCtrl.value); const minStr = Math.min(minStrCtrl.value, maxStrCtrl.value); const maxStr = Math.max(minStrCtrl.value, maxStrCtrl.value); const minPres = Math.min(minPresCtrl.value, maxPresCtrl.value); const maxPres = Math.max(minPresCtrl.value, maxPresCtrl.value); const spread = doc.currentSpread; doc.executeCommand(DocumentCommand.createSetCurrentSpread(spread)); for (const node of selectedNodes) { applyLineDiffusionFill(node, count, minLen, maxLen, minBlur, maxBlur, minStr, maxStr, minPres, maxPres, rCtrl.value, gCtrl.value, bCtrl.value, angleFactor.value,linkcolour.value); } console.log(`Done! Applied to ${selectedNodes.length} node(s).`); } else { console.log('Cancelled.'); } } }